#include <fstream>
#include "Event.h"
#include <sstream>
#include "dateTime.h"
#include "storage.h"
#include "TimedEvent.h"
#include "DeadlineEvent.h"
#include "FloatingEvent.h"


Storage:: Storage(){
   _fileName=FILE_NAME;  // initialize storage object with a designated file name
}



std::string Storage::numberToString(int number){    // convert integer number to a string number
    std::string result;
    std::ostringstream convert;
	convert<<number;
	result=convert.str();
	return result;     
}

std::string Storage::translateDateTimeToString(DateTime dateTime){    // translate information in a date time class into a string
    std::string time;
	Logger::instance()->LogMessage(DateToString);
	time=numberToString(dateTime.getYear())+SLASH+numberToString(dateTime.getMonth())+SLASH+numberToString(dateTime.getDay())+COMMA;
    time += numberToString(dateTime.getHour())+COLON+numberToString(dateTime.getMin())+COMMA;
    return time;
}



std::string Storage::translateToString(Event* task){ 
	std::string input;
	Logger::instance()->LogMessage(EventToString);
	if(isTimedEvent(task)){
		input=TIME_EVENT+COMMA;
		input+=task->getName()+COMMA+task->getImportanceLevel()+COMMA+task->getLocation()+COMMA+numberToString(task->getDisplayID()) +COMMA;
		input+=numberToString(task->getSearchID())+COMMA+task->getEventStatus()+COMMA;
		input+=translateDateTimeToString(((*task).getTimedEventStartTime()))+translateDateTimeToString((*task).getTimedEventEndTime());
	    
	}else{
		if(isDeadlineEvent(task)){
			input=DEADLINE_EVENT+COMMA;
			input+=task->getName()+COMMA+task->getImportanceLevel()+COMMA+task->getLocation()+COMMA+numberToString(task->getDisplayID()) +COMMA;
			input+=numberToString(task->getSearchID())+COMMA+task->getEventStatus()+COMMA;
			input+=translateDateTimeToString((*task).getDeadlineEventEndTime());

		}else{
			input=FLOATING_EVENT+COMMA;
			input+=task->getName()+COMMA+task->getImportanceLevel()+COMMA+task->getLocation()+COMMA+numberToString(task->getDisplayID()) +COMMA;
			input+=numberToString(task->getSearchID())+COMMA+task->getEventStatus()+COMMA;
		    }
	    }
	return input;
}

void Storage::setTaskPriority(std::string stringInfo, Event* task){  // set the importance level for an event accordingly
	
	Logger::instance()->LogMessage(SET_IMPORTANCE);

	if(stringInfo==PRIORITY_HIGH)
		task->setImportanceLevel(PRIORITY_HIGH);
	else
		if(stringInfo==PRIORITY_NORMAL)
			task->setImportanceLevel(PRIORITY_NORMAL);
		else
			task->setImportanceLevel(PRIORITY_LOW);
			
	return;
		
}

void Storage::translateToTimedTask(std::string taskInfo, Event* task){ // translate a string of information to an timedEvent
    unsigned int tStart=0, tEnd=0;
	int i=1;

	std::string stringInfo;
	tEnd=taskInfo.find_first_of(SYMBOL_LIST);

	DateTime startT;
	DateTime endT;

	Logger::instance()->LogMessage(SET_TIME_EVENT_MESSAGE);

	while(tEnd!=std::string::npos){
	stringInfo=taskInfo.substr(tStart,tEnd-tStart);
	tStart=tEnd+1;  
	switch(i){
	    case 1: (*task).setName(stringInfo); break;
		case 2: setTaskPriority(stringInfo,task); break;
		case 3: (*task).setLocation(stringInfo); break;
		case 4: (*task).setDisplayID(atoi(stringInfo.c_str())); break;
		case 5:(*task).setSearchID(atoi(stringInfo.c_str())); break;
		case 6:(*task).setStatus(stringInfo); break;


		case 7: startT.setYear(atoi(stringInfo.c_str())); break;
		case 8: startT.setMonth(atoi(stringInfo.c_str())); break;
		case 9:startT.setDay(atoi(stringInfo.c_str())); break;
		case 10:startT.setHour(atoi(stringInfo.c_str())); break;
		case 11:startT.setMin(atoi(stringInfo.c_str())); break;
		

		case 12: endT.setYear(atoi(stringInfo.c_str())); break;
		case 13: endT.setMonth(atoi(stringInfo.c_str())); break;
		case 14:endT.setDay(atoi(stringInfo.c_str())); break;
		case 15:endT.setHour(atoi(stringInfo.c_str())); break;
		case 16:endT.setMin(atoi(stringInfo.c_str())); break;


		default: break;
    }
	
	
	tEnd=taskInfo.find_first_of(SYMBOL_LIST,tStart);
	i++;
   }
	task->setTimedEventStartTime(startT);
	task->setTimedEventEndTime(endT);
}


void Storage::translateToDeadlineTask(std::string taskInfo, Event* task){    // translate a string information to deadline event
    unsigned int tStart=0, tEnd=0;
	int i=1;

	std::string stringInfo;
	tEnd=taskInfo.find_first_of(SYMBOL_LIST);
	DateTime endTime;

	Logger::instance()->LogMessage(SET_DEADLINE_EVENT_MESSAGE);

	while(tEnd!=std::string::npos){
	stringInfo=taskInfo.substr(tStart,tEnd-tStart);
	tStart=tEnd+1;  
	switch(i){
	    case 1: (*task).setName(stringInfo); break;
		case 2: setTaskPriority(stringInfo,task); break;
		case 3: (*task).setLocation(stringInfo); break;
		case 4: (*task).setDisplayID(atoi(stringInfo.c_str())); break;
		case 5:(*task).setSearchID(atoi(stringInfo.c_str())); break;
		case 6:(*task).setStatus(stringInfo); break;

		case 7: endTime.setYear(atoi(stringInfo.c_str())); break;
		case 8: endTime.setMonth(atoi(stringInfo.c_str())); break;
		case 9: endTime.setDay(atoi(stringInfo.c_str())); break;
		case 10: endTime.setHour(atoi(stringInfo.c_str())); break;
		case 11:endTime.setMin(atoi(stringInfo.c_str())); break;


		default: break;
    }
	
	
	tEnd=taskInfo.find_first_of(SYMBOL_LIST,tStart);
	i++;
   }
	task->setDeadlineEventEndtime(endTime);
}



void Storage::translateToFloatingTask(std::string taskInfo, Event* task){ // translate a string information to floating event
    unsigned int tStart=0, tEnd=0;
	int i=1;

	std::string stringInfo;
	tEnd=taskInfo.find_first_of(SYMBOL_LIST);

	Logger::instance()->LogMessage(SET_FLOATING_EVENT_MESSAGE);

	while(tEnd!=std::string::npos){
	stringInfo=taskInfo.substr(tStart,tEnd-tStart);
	tStart=tEnd+1;  
	switch(i){
	    case 1: (*task).setName(stringInfo); break;
		case 2: setTaskPriority(stringInfo,task); break;
		case 3: (*task).setLocation(stringInfo); break;
		case 4: (*task).setDisplayID(atoi(stringInfo.c_str())); break;
		case 5:(*task).setSearchID(atoi(stringInfo.c_str())); break;
        case 6:(*task).setStatus(stringInfo); break;

		default: break;
    }
	
	tEnd=taskInfo.find_first_of(",/:",tStart);
	i++;
   }
}



void Storage::setTask(Event* task){

	Logger::instance()->LogMessage(STORAGE_PUSH_EVENT);
    _taskList.push_back(task);
     return;
}


std::vector<Event*> Storage::readFile(){

    std::string input,stringType;
	unsigned int tStart=0, tEnd=0;
    
    std::ifstream readFromFile;
    readFromFile.open(_fileName.c_str());
   _taskList.clear();

   Logger::instance()->LogMessage(STORAGE_READFILE);

   while(std::getline(readFromFile,input)){
   tStart=0;
   tEnd=input.find_first_of((SYMBOL_LIST));
   stringType=input.substr(tStart,tEnd-tStart);   // extract out the string type from the each string obtained from the text file and translate accordingly
   input=input.substr(tEnd+1,std::string::npos);

   if(stringType==DEADLINE_EVENT){
	   Event* taskInput=new DeadlineEvent;
       (*taskInput).setEventType(stringType);

	   translateToDeadlineTask(input, taskInput);
	   setTask(taskInput);
	   
   }
   else{
	   if(stringType==TIME_EVENT){
		   Event* taskInput=new TimedEvent;
		   taskInput->setEventType(stringType);
	   
		   translateToTimedTask(input, taskInput);
           setTask(taskInput);
	   
	   }
	   else{
		   Event* taskInput=new FloatingEvent;
		   taskInput->setEventType(stringType);
		   
		   translateToFloatingTask(input, taskInput);
		   setTask(taskInput);
		   


	   }
   }
   }
    readFromFile.close();

    return _taskList;

}




void Storage::writeFile(std::vector<Event*> updatedFile){
  
  std::string input;
  Event* taskInput;
  std::ofstream writeToFile;
  writeToFile.open(_fileName.c_str());

  writeToFile.clear();

  Logger::instance()->LogMessage(STORAGE_WRITEFILE);

  std::vector<Event*> :: iterator iter;
  for(iter=updatedFile.begin();iter!=updatedFile.end();iter++){
         taskInput=*iter;
         input=translateToString(taskInput);
         writeToFile << input<<std::endl;
  }
  writeToFile.close();
  }



// checking the event type for an event


bool Storage::isTimedEvent(Event *task){
	if((*task).getEventType()==TIME)
		return true;
	else
		return false;
}

bool Storage::isFloatingEvent(Event* task){
   if((*task).getEventType()==FLOATING)
        return true;
   else
        return false;
}

bool Storage::isDeadlineEvent(Event* task){
   if((*task).getEventType()==DEADLINE)
        return true;
   else
        return false;
}

